Imports System
Imports System.Collections.Generic
Imports System.Text
Imports System.Xml
Imports System.Collections.ObjectModel
Imports Microsoft.Health.PatientConnect
Imports Microsoft.Health
Imports Microsoft.Health.ItemTypes
Imports Microsoft.Health.Web
Imports System.Globalization

Public NotInheritable Class Functions

    Public Shared ReadOnly Property ApplicationId() As String
        Get
            If System.Configuration.ConfigurationManager.AppSettings("ApplicationId") <> Nothing Then
                Return System.Configuration.ConfigurationManager.AppSettings("ApplicationId").ToString()
            End If
            Return ""
        End Get
    End Property

    ''' <summary>
    ''' Create a participant code. A participant can authorize this application by entering this code
    ''' on HealthVault and answering the security question
    ''' </summary>
    ''' <param name="friendlyName">Participant's Name</param>
    ''' <param name="securityQuestion">Security question</param>
    ''' <param name="securityAnswer">Security Answer</param>
    ''' <param name="applicationPatientId">Application Specific ID for Participant</param>
    ''' <returns>Returns 20 digit identity code</returns>
    Public Shared Function CreateParticipantIdentityCode(ByVal friendlyName As String, ByVal securityQuestion As String, _
            ByVal securityAnswer As String, ByVal applicationPatientId As String) As String
        Dim _applicationId As New Guid(ApplicationId)
        Dim _offlineConnection As OfflineWebApplicationConnection = HealthVaultConnectionManager.CreateConnection(_applicationId)
        Dim _identityCode As String = PatientConnection.Create(_offlineConnection, friendlyName, securityQuestion, securityAnswer, Nothing, applicationPatientId)
        Return _identityCode
    End Function

    ''' <summary>
    ''' Get all the application authorizatons that happend in last n days as specified by the pastDays parameter.
    ''' pastDays is set to 0, this function gets ALL the validatations that has happend to date.
    ''' </summary>
    ''' <param name="pastDays">Specify the last number of days since when the validations needs to be fetched. Specify 0 to fetch all validations</param>
    ''' <returns></returns>
    Public Shared Function GetValidatedConnectionsInPastDays(ByVal pastDays As Integer) As Collection(Of ValidatedPatientConnection)
        Dim appId As New Guid(ApplicationId)
        Dim offlineConnection As OfflineWebApplicationConnection = HealthVaultConnectionManager.CreateConnection(appId)

        If pastDays > 0 Then
            Dim dtSince As DateTime
            dtSince = DateTime.Now.AddDays(-1 * pastDays)
            Return PatientConnection.GetValidatedConnections(offlineConnection, dtSince)
        End If
        Return PatientConnection.GetValidatedConnections(offlineConnection)
    End Function

    ''' <summary>
    ''' Generates an XML Document containing the blood pressure data of participants specified.
    ''' Depending on number of participants and date since paramenter, this request could take some time to complete.
    ''' </summary>
    ''' <param name="dtDateTimeAfter">Specify the date since when blood pressure data is to be downloaded</param>
    ''' <param name="participantList">The list of ParticipantConnectionDetails whose blood pressure details need to be downloaded</param>
    ''' <returns>XmlDocument containg the participant's data</returns>
    Public Shared Function GetParticipantData(ByVal dtDateTimeAfter As DateTime, ByVal participantList As List(Of ParticipantConnectionDetails)) As XmlDocument
        Return ConstructXmlDocument(dtDateTimeAfter, participantList)
    End Function

    Private Shared Function ConstructXmlDocument(ByVal dtDateAfter As DateTime, ByVal participantList As List(Of ParticipantConnectionDetails)) As XmlDocument

        Dim _applicationId As New Guid(ApplicationId)

        Dim xDoc As New XmlDocument()

        Dim declNode As XmlNode = xDoc.CreateNode(XmlNodeType.XmlDeclaration, "", "")
        xDoc.AppendChild(declNode)

        Dim xResultNode As XmlNode = xDoc.CreateNode(XmlNodeType.Element, "result", String.Empty)

        'Populate the current query specific attributes 

        Dim xQueryNode As XmlNode = xDoc.CreateNode(XmlNodeType.Element, "query", String.Empty)

        Dim xQueryWhenNode As XmlNode = xDoc.CreateNode(XmlNodeType.Element, "when", String.Empty)
        xQueryWhenNode.InnerText = DateTime.Now.ToString()
        xQueryNode.AppendChild(xQueryWhenNode)

        Dim xQueryCreatedAfterNode As XmlNode = xDoc.CreateNode(XmlNodeType.Element, "created_after", String.Empty)
        xQueryCreatedAfterNode.InnerText = dtDateAfter.ToString()
        xQueryNode.AppendChild(xQueryCreatedAfterNode)

        Dim xQueryLoggedInAccountNode As XmlNode = xDoc.CreateNode(XmlNodeType.Element, "loggedin_account", String.Empty)
        xQueryLoggedInAccountNode.InnerText = "application-" + ApplicationId
        xQueryNode.AppendChild(xQueryLoggedInAccountNode)

        Dim xQueryAuthRecordCountNode As XmlNode = xDoc.CreateNode(XmlNodeType.Element, "num_participant_records_fetched", String.Empty)
        xQueryAuthRecordCountNode.InnerText = participantList.Count.ToString()
        xQueryNode.AppendChild(xQueryAuthRecordCountNode)

        xResultNode.AppendChild(xQueryNode)

        Dim xUsersNode As XmlNode = xDoc.CreateNode(XmlNodeType.Element, "users", String.Empty)

        For Each participantDetail As ParticipantConnectionDetails In participantList
            Dim personId As Guid = participantDetail.PersonId

            Dim recordId As Guid = participantDetail.RecordId

            Dim accessor As New HealthRecordAccessor(HealthVaultConnectionManager.CreateConnection(_applicationId, personId), recordId)
            Dim xUserNode As XmlNode = xDoc.CreateNode(XmlNodeType.Element, "user", String.Empty)

            Dim xApplicationSpecificIdAttrib As XmlAttribute = xDoc.CreateAttribute("application_specific_id")
            xApplicationSpecificIdAttrib.Value = participantDetail.ApplicationSpecificId
            xUserNode.Attributes.Append(xApplicationSpecificIdAttrib)

            Dim xNameAttrib As XmlAttribute = xDoc.CreateAttribute("healthvault_record_name")

            'Fetch the Personal and Contact item from HealthVault for this user. 
            'For efficiency, batch the requests 
            Dim _personal As Personal
            Dim _contact As Contact
            _personal = Nothing
            _contact = Nothing

            Dim searcher_userInfo As New HealthRecordSearcher(accessor)

            Dim filter_personal As New HealthRecordFilter()
            filter_personal.TypeIds.Add(Personal.TypeId)
            filter_personal.View.Sections = HealthRecordItemSections.Core Or HealthRecordItemSections.Xml
            searcher_userInfo.Filters.Add(filter_personal)

            Dim filter_contact As New HealthRecordFilter()
            filter_contact.TypeIds.Add(Contact.TypeId)
            filter_contact.View.Sections = HealthRecordItemSections.Core Or HealthRecordItemSections.Xml
            searcher_userInfo.Filters.Add(filter_contact)

            Dim results_userInfo As ReadOnlyCollection(Of HealthRecordItemCollection) = searcher_userInfo.GetMatchingItems()

            Dim items_personal As HealthRecordItemCollection = results_userInfo(0)

            Dim items_contact As HealthRecordItemCollection = results_userInfo(1)

            If (items_personal IsNot Nothing) AndAlso (items_personal.Count > 0) Then
                _personal = TryCast(items_personal(0), Personal)
            End If

            If (items_contact IsNot Nothing) AndAlso items_contact.Count > 0 Then
                _contact = TryCast(items_contact(0), Contact)
            End If

            'Find the name as in healthvault from the Personal Item of the user
            If (_personal IsNot Nothing) AndAlso (_personal.Name IsNot Nothing) Then
                xNameAttrib.Value = _personal.Name.Full
            Else
                xNameAttrib.Value = ""
            End If
            xUserNode.Attributes.Append(xNameAttrib)

            'Find the email as in healthvault from the Contact Item of the user
            If (_contact IsNot Nothing) Then
                Dim xEmailAttrib As XmlAttribute = xDoc.CreateAttribute("email")
                If (_contact.ContactInformation IsNot Nothing) AndAlso _
                   (_contact.ContactInformation.PrimaryEmail IsNot Nothing) AndAlso _
                   (_contact.ContactInformation.PrimaryEmail.Address IsNot Nothing) Then
                    xEmailAttrib.Value = _contact.ContactInformation.PrimaryEmail.Address
                    xUserNode.Attributes.Append(xEmailAttrib)
                End If
            End If

            'Finally, Query for the blood pressure readings
            Dim searcher As New HealthRecordSearcher(accessor)
            Dim filter As New HealthRecordFilter()
            filter.TypeIds.Add(BloodPressure.TypeId)
            filter.CurrentVersionOnly = True
            filter.EffectiveDateMin = dtDateAfter
            filter.View.Sections = HealthRecordItemSections.Core Or HealthRecordItemSections.Xml
            searcher.Filters.Add(filter)
            Dim results As ReadOnlyCollection(Of HealthRecordItemCollection) = searcher.GetMatchingItems()
            Dim resultCollection As HealthRecordItemCollection = results(0)

            Dim xReadingCountAttrib As XmlAttribute = xDoc.CreateAttribute("num_blood_pressure_readings")
            xReadingCountAttrib.Value = resultCollection.Count.ToString()
            xUserNode.Attributes.Append(xReadingCountAttrib)

            'Add the item xml of the blood pressure reading to current user node 
            For Each item As HealthRecordItem In resultCollection
                Dim itemXMLString As String = item.GetItemXml()
                xUserNode.InnerXml += itemXMLString
            Next
            xUsersNode.AppendChild(xUserNode)
        Next
        xResultNode.AppendChild(xUsersNode)
        xDoc.AppendChild(xResultNode)
        Return xDoc
    End Function
End Class

